package com.hzit.hzb.core.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hzit.hzb.core.pojo.dto.ExcelDictDTO;
import com.hzit.hzb.core.pojo.entity.Dict;
import com.hzit.hzb.core.mapper.DictMapper;
import com.hzit.hzb.core.service.DictService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 数据字典 服务实现类
 * </p>
 *
 * @author hbxfwf
 * @since 2024-08-27
 */
@Service
@Slf4j
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {

	@Autowired
	private RedisTemplate redisTemplate;

	//1. 读取上传Excel文件并写入到数据库中
	@Override
	public void importData(InputStream inputStream) {
		// 1.1 根据上传的文件流读取excel文件
		// EasyExcel.read(inputStream,new MyReadListener(this)).sheet().doRead();
		EasyExcel.read(inputStream,ExcelDictDTO.class,new MyReadListener(this)).sheet().doRead();
	}
	//2. 将数据库中的数据写出到excel文件中
	@Override
	public List<ExcelDictDTO> listDictData() {
		// 2.1 查询出数据库中的数据
		List<Dict> list = this.list();
		// 2.2 将dict集合转换为dto集合
		List<ExcelDictDTO> collect = list.stream().map(m -> {
			ExcelDictDTO dto = new ExcelDictDTO();
			BeanUtils.copyProperties(m, dto);
			return dto;
		}).collect(Collectors.toList());

		return collect;
	}

	/**
	 * 根据父id查询子节点列表
	 * @param pid
	 * @return
	 */
	@Override
	public List<Dict> findByPid(Integer pid) {
		// 1. 从redis中得到根据字典的父id，得到其下的字典列表
		List<Dict> dicts = null;
		try {
			dicts = (List<Dict>) redisTemplate.opsForValue().get("hzb:core:dictList:" + pid);
			if(CollectionUtil.isNotEmpty(dicts)){
				log.info("从redis中查询出父id为{}的字典列表{}",pid,dicts);
				return dicts;
			}
		} catch (Exception e) {
			log.error("查询redis出现故障:{}",e.getMessage());
		}

		// 2. 从数据库中得到数据
		log.info("正在从数据库中查询字典。");
		dicts = this.list(new QueryWrapper<Dict>().eq("parent_id", pid));
		dicts.forEach(dict -> {
			Long id = dict.getId();
			// 以此id这父id查询其下是否有子节点
			boolean hasChildren = isHasChildren(id);
			// 为当前节点设置它的hasChildren属性
			dict.setHasChildren(hasChildren);
		});

		// 3. 将从数据库中取得的数据放到redis中
		try {
			redisTemplate.opsForValue().set("hzb:core:dictList:" + pid,dicts,100, TimeUnit.DAYS);
		} catch (Exception e) {
			log.error("保存到redis中出现故障，原因：{}",e.getMessage());
		}

		return dicts;
	}

	/**
	 * 根据字典code查询字典列表
	 * @param dictCode
	 * @return
	 */
	@Override
	public List<Dict> findByDictCode(String dictCode) {
		// 1. 根据dictCode查询字典对象
		Dict dict = this.getOne(new QueryWrapper<Dict>().eq("dict_code", dictCode));
		List<Dict> dictList = findByPid(new Integer(dict.getId() + ""));
		return dictList;
	}

	/**
	 * 判断以指定的id为父id，是否存在这样的节点
	 * @param id
	 * @return
	 */
	private boolean isHasChildren(Long id) {
		return  this.count(new QueryWrapper<Dict>().eq("parent_id", id)) > 0;
	}


}
@Slf4j
class MyReadListener extends AnalysisEventListener<ExcelDictDTO>{
	private DictService dictService;
	public MyReadListener(DictService dictService){
		this.dictService = dictService;
	}
	// 读次最多读10条
	private static int BATCH_SIZE = 10;
	private List<ExcelDictDTO> dtos = new ArrayList<>();
	/**
	 * 每读一行执行一次
	 * @param dto
	 * @param analysisContext
	 */
	@Override
	public void invoke(ExcelDictDTO dto, AnalysisContext analysisContext) {
		//1. 每次向集合中添加一条数据
		dtos.add(dto);
		// 2. 当加到10条之后就保存一次
		if(BATCH_SIZE < dtos.size()){
			save(dtos);
			dtos.clear();
		}
	}

	/**
	 * 批量保存数据
	 * @param dtos
	 */
	private void save(List<ExcelDictDTO> dtos) {
		// 1. 将dtos集合转换为List<Dict>
		List<Dict> dicts = new ArrayList<>();
		dtos.forEach(dto -> {
			Dict dict = new Dict();
			BeanUtils.copyProperties(dto,dict);
			dicts.add(dict);
		});
		dictService.saveBatch(dicts);
	}

	/**
	 * 最后读取完成后执行的回调
	 * @param analysisContext
	 */
	@Override
	public void doAfterAllAnalysed(AnalysisContext analysisContext) {
		save(dtos);
		log.info("保存数据完毕!");
	}
}
